﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Timers;
using System.Windows.Threading;

namespace MuzičkiFeršterker
{
    /// <summary>
    /// Class used as music engine handler
    /// </summary>
    class PlayHandler : IPlay
    {
        private Play_ currentPlay;

        private TextBlock elapsedLabel;
        private TextBlock remainingLabel;
        private TextBlock titleLabel;
        private Slider timeSlider;

        private bool paused;
        private bool stop;
        private Timer timer;

        public delegate void RequestNextSong();
        public event RequestNextSong onRequestNextSong;

        /// <summary>
        /// Default constructor
        /// </summary>
        public PlayHandler()
        {
            paused = false;
            stop = false;
            timer = new Timer(100.0);
            timer.Elapsed += timerTick;
            timer.Start();
        }

        /// <summary>
        /// Method used to set next song
        /// </summary>
        /// <param name="song">Song used to be as next song</param>
        public void SetSong(Song song)
        {
            switch (song.Engine)
            {
                case Engine.irrKlang:
                    if (currentPlay != null)
                        currentPlay.Stop();
                    currentPlay = new Play_irrKlang(song);
                    break;

                case Engine.MediaElement:
                    if (currentPlay != null)
                        currentPlay.Stop();
                    currentPlay = new Play_MediaElement(song);
                    break;

                default:
                    return;
            }
            paused = false;
            if (timeSlider != null)
            {
                timeSlider.Maximum = currentPlay.Duration;
                timeSlider.ValueChanged += timeSlider_ValueChanged;
            }

            if (titleLabel != null)
            {
                titleLabel.Dispatcher.Invoke((Action)delegate()
                {
                    titleLabel.Text = song.Name;
                });
            }
        }

        /// <summary>
        /// Method used to handle Time Slider value changes
        /// </summary>
        /// <param name="sender">sender object</param>
        /// <param name="e">Event arguments</param>
        void timeSlider_ValueChanged(object sender, System.Windows.RoutedPropertyChangedEventArgs<double> e)
        {
            if (Math.Abs(e.OldValue - e.NewValue) > 1000)
                currentPlay.setPosition((int)e.NewValue);
        }

        #region IPlay Members
        /// <summary>
        /// Starts the playback
        /// </summary>
        public void Play()
        {
            stop = false;
            paused = false;
            currentPlay.Play();
        }

        /// <summary>
        /// Starts or pauses the playback
        /// </summary>
        public void PlayPause()
        {
            if (paused)
            {
                Resume();
            }
            else
            {
                Pause();
            }
        }

        /// <summary>
        /// Pauses the playback
        /// </summary>
        public void Pause()
        {
            paused = true;
            currentPlay.Pause();
        }

        /// <summary>
        /// Resumes the playback
        /// </summary>
        public void Resume()
        {
            currentPlay.Resume();
            paused = false;
        }

        /// <summary>
        /// Stops the playback (pause and time reset to 0)
        /// </summary>
        public void Stop()
        {
            currentPlay.Stop();
            stop = true;
        }

        /// <summary>
        /// Obsolete, only here because of implementing IPlay interface
        /// </summary>
        /// <returns>NOTHING</returns>
        [Obsolete("For the sole purpose of implementing the IPlay interface")]
        public int getPosition()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Obsolete, only here because of implementing IPlay interface
        /// </summary>
        /// <returns>NOTHING</returns>
        [Obsolete("For the sole purpose of implementing the IPlay interface")]
        public void setPosition(int pos)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Obsolete, only here because of implementing IPlay interface
        /// </summary>
        /// <returns>NOTHING</returns>
        [Obsolete("For the sole purpose of implementing the IPlay interface")]
        public bool isFinished()
        {
            throw new NotImplementedException();
        }
        #endregion

        #region Graphical Elements
        /// <summary>
        /// Sets the MediaElement used to play Windows Media files
        /// </summary>
        /// <param name="a">MediaElement used as engine</param>
        public void SetMediaElement(MediaElement a)
        {
            Play_.SetMediaElement(a);
        }

        /// <summary>
        /// Sets the TextBlock used as Elapsed Time display
        /// </summary>
        /// <param name="a">WPF text block element</param>
        public void SetElapsedLabel(TextBlock a)
        {
            elapsedLabel = a;
        }

        /// <summary>
        /// Sets the TextBlock used as Remaining Time display
        /// </summary>
        /// <param name="a">WPF text block element</param>
        public void SetRemainingLabel(TextBlock a)
        {
            remainingLabel = a;
        }

        /// <summary>
        /// Slider used as Time slider display
        /// </summary>
        /// <param name="a">WPF Slider element</param>
        public void SetTimeSlider(Slider a)
        {
            timeSlider = a;
        }

        /// <summary>
        /// TextBlock used to display title and artist of current song
        /// </summary>
        /// <param name="a">WPF TextBlock element</param>
        public void SetTitleLabel(TextBlock a)
        {
            titleLabel = a;
        }
        #endregion

        #region Volume / Balance settings
        /// <summary>
        /// Gets or sets the volume. 0 is silence, 100 is maximum
        /// </summary>
        public int Volume
        {
            get { return currentPlay.Volume; }
            set 
            { 
                if(currentPlay != null)
                    currentPlay.Volume = value; 
            }
        }

        /// <summary>
        /// Gets or sets the left/right output balance. -100 is 100% left, 0 is centered, 100 is 100% right
        /// </summary>
        public int Balance
        {
            get { return currentPlay.Balance; }
            set { currentPlay.Balance = value; }
        }
        #endregion

        #region Timer stuff
        /// <summary>
        /// Timer tick method, used to handle any time-related functions
        /// </summary>
        /// <param name="o">Sender object</param>
        /// <param name="e">Event arguments</param>
        private void timerTick(object o, ElapsedEventArgs e)
        {
            try
            {
                if (currentPlay != null)
                {
                    uint position = (uint)currentPlay.getPosition();
                    uint duration = (uint)currentPlay.Duration;
                    elapsedLabel.Dispatcher.Invoke((Action)delegate()
                    {
                        elapsedLabel.Text = this.millisecondsToString(position);
                    });

                    remainingLabel.Dispatcher.Invoke((Action)delegate()
                    {
                        remainingLabel.Text = this.millisecondsToString(duration - position);
                    });

                    timeSlider.Dispatcher.Invoke((Action)delegate()
                    {
                        timeSlider.Value = position;
                    });

                    /* FINISHED STUFF */
                    if (paused == false && currentPlay.isFinished() && onRequestNextSong != null && !stop)
                        onRequestNextSong();
                }
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.Message.ToString());
            }
        }
        #endregion

        #region conversion stuff

        /// <summary>
        /// Converts uint milliseconds to time string
        /// </summary>
        /// <param name="ms">time in ms</param>
        /// <returns>hh:mm:ss</returns>
        private string millisecondsToString(uint ms)
        {
            string vrni = "";

            ms = ms - (ms % 1000);
            ms /= 1000;
            vrni = ms.ToString();
            string minute = (ms / 60).ToString();
            if (minute.Length < 2)
                minute = "0" + minute;
            string sekunde = (ms - (60 * (ms / 60))).ToString();
            if (sekunde.Length < 2)
                sekunde = "0" + sekunde;

            vrni = minute + ":" + sekunde;
            return vrni;
        }
        #endregion
    }
}
